{
 "cells": [
  {
   "cell_type": "markdown",
   "id": "1d782de1-5405-4cf5-84b8-1cf4c4b063f3",
   "metadata": {},
   "source": [
    "# LCEL接口\n",
    "- 输入格式\n",
    "- 输出格式\n",
    "- 8种不同的接口方式"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "1848de14-e0d5-4934-94a1-38d3d5ddb732",
   "metadata": {},
   "outputs": [],
   "source": [
    "from langchain_core.prompts import ChatPromptTemplate\n",
    "from langchain_openai import ChatOpenAI\n",
    "\n",
    "model = ChatOpenAI(\n",
    "    model=\"gpt-3.5-turbo\",\n",
    ")\n",
    "prompt = ChatPromptTemplate.from_template(\"给我讲一个关于{topic}的笑话\")\n",
    "chain = prompt | model"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "3e698dd3-45d0-4afc-bf24-5588df181843",
   "metadata": {},
   "source": [
    "## input schema"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "4885bf4a-49ee-4401-9389-962f3078d7d0",
   "metadata": {},
   "outputs": [],
   "source": [
    "chain.input_schema.schema()\n",
    "# {'title': 'PromptInput',\n",
    "#  'type': 'object',\n",
    "#  'properties': {'topic': {'title': 'Topic', 'type': 'string'}}}\n",
    "\n",
    "prompt.input_schema.schema()\n",
    "\n",
    "model.input_schema.schema()"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "4714eb20-1762-4565-aca2-346766626615",
   "metadata": {},
   "source": [
    "## Output Schema"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "68fb6b1d-fc9e-4a3a-be0a-d1110cc0a88e",
   "metadata": {},
   "outputs": [],
   "source": [
    "chain.output_schema.schema()"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "53400d3d-6087-45e3-8a8f-5ff28b62f2db",
   "metadata": {},
   "source": [
    "## 输出"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "6004fd09-46fc-4067-8382-037585ade4d0",
   "metadata": {},
   "outputs": [],
   "source": [
    "# Stream（流式）\n",
    "for s in chain.stream({\"topic\": \"熊\"}):\n",
    "    print(s.content, end=\"\", flush=True)\n",
    "\n",
    "# Invoke\n",
    "chain.invoke({\"topic\": \"熊\"})\n",
    "\n",
    "# batch\n",
    "chain.batch([{\"topic\": \"熊\"}, {\"topic\": \"猫\"}], config={\"max_concurrency\": 5}) # 可设置并发数\n",
    "\n",
    "# Async Stream 异步\n",
    "async for s in chain.astream({\"topic\": \"女人\"}):\n",
    "    print(s.content, end=\"\", flush=True)\n",
    "\n",
    "# Async Invoke\n",
    "await chain.ainvoke({\"topic\": \"男人\"})\n",
    "\n",
    "# Async Batch\n",
    "await chain.abatch([{\"topic\": \"熊\"},{\"topic\": \"女人\"}])"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "33d95971-0cb2-4a0b-be26-b167683f7f12",
   "metadata": {},
   "source": [
    "## 异步获取中间步骤"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "132de117-8095-4a99-967b-ab842d4bc339",
   "metadata": {},
   "outputs": [],
   "source": [
    "from langchain_community.vectorstores import FAISS\n",
    "from langchain_core.output_parsers import StrOutputParser\n",
    "from langchain_core.runnables import RunnablePassthrough\n",
    "from langchain_openai import OpenAIEmbeddings\n",
    "\n",
    "template = \"\"\"基于下面的上下文来回答问题:\n",
    "{context}\n",
    "\n",
    "Question: {question}\n",
    "\"\"\"\n",
    "prompt = ChatPromptTemplate.from_template(template)\n",
    "\n",
    "vectorstore = FAISS.from_texts(\n",
    "    [\"柯基犬是一种中型家庭宠物犬\"], embedding=OpenAIEmbeddings()\n",
    ")\n",
    "retriever = vectorstore.as_retriever()\n",
    "\n",
    "retrieval_chain = (\n",
    "    {\n",
    "        \"context\": retriever.with_config(run_name=\"Docs\"),\n",
    "        \"question\": RunnablePassthrough(),\n",
    "    }\n",
    "    | prompt\n",
    "    | model\n",
    "    | StrOutputParser()\n",
    ")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "c9f7dbbb-a2a6-4b9d-8c98-860e7882ce9b",
   "metadata": {},
   "outputs": [],
   "source": [
    "async for chunk in retrieval_chain.astream_log(\n",
    "    \"柯基是什么?\", include_names=[\"Docs\"]\n",
    "):\n",
    "    print(\"-\" * 40)\n",
    "    print(chunk)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "cf248d00-ac8b-4848-967e-6bc78037b9b6",
   "metadata": {},
   "source": [
    "## 并行支持"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "81c21b2a-6953-44a4-964c-2e2e5a848021",
   "metadata": {},
   "outputs": [],
   "source": [
    "from langchain_core.runnables import RunnableParallel\n",
    "\n",
    "chain1 = ChatPromptTemplate.from_template(\"给我讲一个关于{topic}的笑话\") | model\n",
    "chain2 = (\n",
    "    ChatPromptTemplate.from_template(\"写两行关于{topic}的诗歌\")\n",
    "    | model\n",
    ")\n",
    "combined = RunnableParallel(joke=chain1, poem=chain2)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "19faebe9-aafd-4477-bf6f-cf805b46e812",
   "metadata": {},
   "outputs": [],
   "source": [
    "%%time\n",
    "combined.invoke({\"topic\": \"熊\"})"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "efa23afe-5fc9-4c00-9cbf-2c979c71c347",
   "metadata": {},
   "outputs": [],
   "source": [
    "# 并行批处理，适用于大量生成\n",
    "%%time\n",
    "combined.batch([{\\\"topic\\\": \\\"熊\\\"}, {\\\"topic\\\": \\\"猫\\\"}])"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python (langchain)",
   "language": "python",
   "name": "langchain-env"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.13.0"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 5
}
